package com.kpmg.datalake.common.controller;

import static com.kpmg.datalake.common.thirdparty.kpmgladp.KpmgLadpInterface.searchUserName;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidPooledConnection;
import com.alibaba.fastjson.JSONObject;
import com.kpmg.datalake.common.constants.Constants;
import com.kpmg.datalake.common.dao.RbacFunctionMapper;
import com.kpmg.datalake.common.dynamicdatasource.DataSourceStoreService;
import com.kpmg.datalake.common.dynamicdatasource.DatabaseDTO;
import com.kpmg.datalake.common.dynamicdatasource.DynamicDataSource;
import com.kpmg.datalake.common.enums.PersonParamEnum;
import com.kpmg.datalake.common.enums.ResultCodeEnum;
import com.kpmg.datalake.common.enums.SystemDeploymentTypeEnum;
import com.kpmg.datalake.common.enums.SystemParamsEnum;
import com.kpmg.datalake.common.enums.UseOrDelEnum;
import com.kpmg.datalake.common.exception.BusinessException;
import com.kpmg.datalake.common.service.IComSystemParamsService;
import com.kpmg.datalake.common.service.IPersonParamsSettingService;
import com.kpmg.datalake.common.service.IPrvgUsrService;
import com.kpmg.datalake.common.service.RbacFunctionService;
import com.kpmg.datalake.common.service.UserManagementService;
import com.kpmg.datalake.common.utils.ContextHolderUtils;
import com.kpmg.datalake.common.utils.CookieUtils;
import com.kpmg.datalake.common.utils.EncrypUtil;
import com.kpmg.datalake.common.utils.ExceptionUtil;
import com.kpmg.datalake.common.utils.SpringUtil;
import com.kpmg.datalake.common.vo.LoginInfoVO;
import com.kpmg.datalake.common.vo.RbacVo;
import com.kpmg.datalake.common.vo.ServerResponse;
import com.kpmg.datalake.common.vo.UserDTO;
import com.kpmg.datalake.common.vo.UserManagementDTO;
import com.kpmg.datalake.common.vo.UserManagementVO;
import com.kpmg.datalake.db.model.SysUsr;
import com.kpmg.datalake.operatelog.annotation.OptLog;
import com.kpmg.datalake.operatelog.enums.LogTypeEnum;
import com.kpmg.datalake.operatelog.utils.IpUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
import org.springframework.web.util.WebUtils;

/**
 * @author: Richard.ji [drichard.ji@kpmg.com]
 * @ate: 2018-07-05 10:35:02
 * @Description: 用户管理
 */
@RestController
@RequestMapping("/userManager")
public class UserManagementController extends BaseController {

  private static final Logger logger = LoggerFactory.getLogger(UserManagementController.class);

  @Resource
  private IPrvgUsrService prvgUsrService;

  @Resource
  private UserManagementService userManagementService;

  @Resource
  private RbacFunctionService rbacFunctionService;

  @Resource
  private RbacFunctionMapper rbacFunctionMapper;
  @Resource
  private IPersonParamsSettingService personParamsSettingService;
  @Resource
  private IComSystemParamsService comSystemParamsService;

  /**
   * 获取用户信息
   */
  @PostMapping(value = "/getUserInfo")
  public ServerResponse getUserInfoList(@RequestBody UserManagementVO userManagementVO) {
    logger.info("获取用户信息");

    try {
      UserManagementDTO user = convertDTO(userManagementVO);

      return userManagementService.getUserInfoList(user);
    } catch (Exception e) {
      logger.error("获取用户信息失败,异常{}", e);
      return ServerResponse.createByErrorMessage("获取用户信息失败");
    }
  }

  @PostMapping("/logout")
  @OptLog(logType = LogTypeEnum.SECURITY, module = "system", description = "用户登出")
  public ServerResponse<String> logout(HttpSession session) {
    session.invalidate();
    return super.doError(ResultCodeEnum.CODE0002, "注销成功");
  }

  @GetMapping(value = "/getDbInfo")
  public ServerResponse<JSONObject> getDbInfo() {
    DynamicDataSource dataSource = SpringUtil.getBean(DynamicDataSource.class);
    JSONObject job = new JSONObject();
    try {
      DruidDataSource druid = (DruidDataSource) ((DruidPooledConnection) dataSource.getConnection())
          .getConnectionHolder().getDataSource();
      job.put("url", druid.getUrl());
      job.put("username", druid.getUsername());
      job.put("password", druid.getPassword());
      DataSourceStoreService dataSourceStoreService = SpringUtil
          .getBean(DataSourceStoreService.class);
      List<DatabaseDTO> databaseDTOList = new ArrayList<>();
      for (Map.Entry<Object, Object> obj : dataSourceStoreService.getMemoryDataSource()
          .entrySet()) {
        DatabaseDTO databaseDTO = new DatabaseDTO();
        DruidDataSource druidDataSource = (DruidDataSource) obj.getValue();
        databaseDTO.setPassword(druidDataSource.getPassword());
        databaseDTO.setUserName(druidDataSource.getUsername());
        databaseDTO.setDbType(druidDataSource.getDbType());
        databaseDTO.setUrl(druidDataSource.getUrl());
        databaseDTOList.add(databaseDTO);
      }
      job.put("dynamicDataSource", databaseDTOList);
    } catch (Exception e) {
      return ExceptionUtil.getExceptionMsg(e);
    }

    return super.doSuccess(job);
  }

  /**
   * 保存用户信息
   *
   * @param userManagementVO userManagementVO
   * @return ServerResponse
   */
  @PostMapping(value = "/saveUser")
  public ServerResponse saveUser(@RequestBody UserManagementVO userManagementVO) {
    logger.info("保存用户信息");
    try {
      UserManagementDTO user = convertDTO(userManagementVO);
      return userManagementService.saveUser(user);
    } catch (Exception e) {
      logger.error("保存用户信息失败,异常{}", e);
      return super.doError("保存用户信息失败");
    }
  }


  /**
   * 修改用户信息
   *
   * @param userManagementVO userManagementVO
   * @return ServerResponse
   */
  @PostMapping(value = "/updateUser")
  public ServerResponse updateUser(@RequestBody UserManagementVO userManagementVO) {

    logger.info("修改用户信息");

    try {
      if (!StringUtils.isEmpty(userManagementVO.getUserId())) {
        UserManagementDTO user = convertDTO(userManagementVO);
        return userManagementService.updateUser(user);
      } else {
        return super.doError(ResultCodeEnum.CODE4000, "参数不能为空");
      }
    } catch (Exception e) {
      logger.error("修改用户信息失败,异常{}", e);
      return super.doError("修改用户信息失败");
    }
  }


  /**
   * 删除用户信息
   *
   * @param userManagementVO userManagementVO
   * @return ServerResponse
   */
  @PostMapping(value = "/deleteUser")
  public ServerResponse deleteUser(@RequestBody UserManagementVO userManagementVO) {

    logger.info("删除用户信息");

    try {
      if (!StringUtils.isEmpty(userManagementVO.getUserId())) {
        UserManagementDTO user = convertDTO(userManagementVO);
        user.setDeleteId(UseOrDelEnum.USE.getCode());
        return userManagementService.deleteUser(user);
      } else {
        return super.doError(ResultCodeEnum.CODE4000, "参数不能为空");
      }
    } catch (Exception e) {
      logger.error("删除用户信息失败,异常{}", e);
      return super.doError("删除用户信息失败");
    }
  }

  /**
   * 获取用户salt
   * @param loginInfo
   * @return
   */
  @PostMapping(value = "/getSaltForUser")
  public ServerResponse getSaltForUser(@RequestBody LoginInfoVO loginInfo) {
    String username = loginInfo.getUsername();
    ServerResponse<SysUsr> usrServerResponse = prvgUsrService.checkUserName(username);
    String salt = "";
    if(!StringUtils.isEmpty(usrServerResponse.getData())){
      salt = usrServerResponse.getData().getSalt();
    }

    return doSuccess(salt);
  }

  @PostMapping(value = "/checkLogin")
  @OptLog(logType = LogTypeEnum.SECURITY, module = "system", description = "登录接口")
  public ServerResponse checkLogin(@RequestBody LoginInfoVO loginInfo, HttpServletRequest request,
      HttpServletResponse response) {
    try {
      String username = loginInfo.getUsername();
      String password = loginInfo.getPassword();
      boolean isRemember = loginInfo.isRemember();
      ContextHolderUtils.setUserName(username);
      logger.info("用户:{}尝试登录系统", username);
      String deploymentType = comSystemParamsService
          .getSystemParamsByCode(SystemParamsEnum.DEPLOYMENT_TYPE.getCode(),
              SystemDeploymentTypeEnum.EXTERNAL.getCode());
      if (SystemDeploymentTypeEnum.INTERNAL.getCode().equals(deploymentType)) {
        return checkIsAD(username);
      } else if (SystemDeploymentTypeEnum.EXTERNAL.getCode().equals(deploymentType)) {
        String loginIp = IpUtils.getIpAddress(request);
        if (StringUtils.isEmpty(username)) {
          return super.doError(ResultCodeEnum.CODE4024);
        }
        //检查当前用户的登录状态是否锁定
        ServerResponse<String> userLoginStatusSR = userManagementService.checkUserLoginStatus(username, loginIp);
        if(!userLoginStatusSR.isSuccess()) {
          logger.info("用户登录状态被锁定");
          return userLoginStatusSR;
        }

        //用户信息校验
        ServerResponse<SysUsr> usrServerResponse = prvgUsrService.checkUserName(username);
        if (!usrServerResponse.isSuccess()) {
          return usrServerResponse;
        }
        SysUsr user = usrServerResponse.getData();
        if (StringUtils.isEmpty(password) && !this.ldapAuthentication(username)) {
          return super.doError(ResultCodeEnum.CODE4017);
        }

        if (!StringUtils.isEmpty(password) && !ObjectUtils
            .nullSafeEquals(password, user.getUsrPwd())) {
          return userManagementService.updateUserLoginDetail(username, loginIp, Boolean.FALSE);
        }

        // 登录成功，覆盖原先的缓存数据，用户错误次数记为0
        userManagementService.updateUserLoginDetail(username, loginIp, Boolean.TRUE);
        // 载入用户配置权限、菜单信息
        user = prvgUsrService.loadUserSettings(user);
        // 设置到Session中
        UserDTO userDTO = new UserDTO();
        BeanUtils.copyProperties(user, userDTO);
        ContextHolderUtils.setLoginUser(userDTO);
        CookieUtils.userRemember(isRemember, username, request, response);
        this.settingLang(request);
      } else {
        throw new BusinessException(ResultCodeEnum.CODE9999, "未知的业务类型");
      }
    } catch (Exception e) {
      logger.error("用户:{}登录系统失败,异常{}", loginInfo.getUsername(), e);
      return super.doError("用户登录系统失败\n" + e.getLocalizedMessage());
    }
    return super.doSuccess("用户登录系统成功");
  }

  /**
   * 自动
   *
   * @param request request
   */
  private void settingLang(HttpServletRequest request) {
    try {
      String paramsByType = personParamsSettingService
          .getPersonParamsByType(PersonParamEnum.AcceptLang.getCode());
      if (!StringUtils.isEmpty(paramsByType)) {
        WebUtils.setSessionAttribute(request, SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME,
            new Locale(paramsByType));
      }
    } catch (Exception e) {
      logger.error("setting lang error", e.getLocalizedMessage());
    }
  }

  /**
   * 获取当前用户的菜单信息
   *
   * @return ServerResponse
   */
  @PostMapping("/userMenu")
  public ServerResponse<JSONObject> getUserMenu() {
    try {
      //获取用户有权限的菜单
      UserDTO loginUser = ContextHolderUtils.getLoginUser();
      RbacVo rbacVo = new RbacVo();
      rbacVo.setUserId(loginUser.getUsrId());
      ServerResponse functionList = rbacFunctionService.rbacFunctionTreeJsonObject(rbacVo);
      if (!functionList.isSuccess()) {
        return super.doError(ResultCodeEnum.CODE9999, functionList.getMsg());
      }
      //获取用户项目列表
      List<Map<String, Object>> projectList = rbacFunctionMapper
          .selectProjectList(loginUser.getUsrId());
      //获取用户基本信息
      Map<String, Object> userInfo = rbacFunctionMapper.selectUserByUserId(loginUser.getUsrId());
      userInfo
          .put("USR_ACC", EncrypUtil.decryptAes(userInfo.get("USR_ACC") + "", Constants.ENCRY_KEY));
      JSONObject result = new JSONObject();
      result.put("functionList", functionList);
      result.put("projectList", projectList);
      result.put("userInfo", userInfo);
      return super.doSuccess(result);
    } catch (Exception e) {
      return super.doError(e.getMessage());
    }

  }

  private ServerResponse checkIsAD(String username) {
    if (this.ldapAuthentication(username)) {
      return ServerResponse.createBySuccess();
    } else {
      return ServerResponse.createByErrorCodeMessage(ResultCodeEnum.CODE4022.getCode(),
          ResultCodeEnum.CODE4022.getDisplay());
    }
  }

  /**
   * 如果是内部部署，使用AD验证。
   */
  private boolean ldapAuthentication(String username) {
    try {
      if (searchUserName(username) == null) {
        return false;
      } else {
        if (logger.isDebugEnabled()) {
          logger.debug("ladp 系统 验证用户{} ", username);
        }
        return true;
      }
    } catch (Exception e) {
      logger.error("AD验证失败", e);
      return false;
    }
  }

  private UserManagementDTO convertDTO(UserManagementVO userManagementVO) {
    UserManagementDTO user = new UserManagementDTO();

    if (!StringUtils.isEmpty(userManagementVO)) {
      BeanUtils.copyProperties(userManagementVO, user);
    }

    return user;
  }

  /**
   * 校验用户session是否存在
   *
   * @return session
   */
  @PostMapping("/checkSession")
  public ServerResponse<String> checkSession() {
    return super.doSuccess(ContextHolderUtils.getSession().getId());
  }
}
